1. Field of the Invention
The present invention relates to computer programming, and deals more particularly with methods, systems, and computer program products for improving the manner in which classes are dynamically loaded during program execution.
2. Description of the Related Art
There are a number of approaches to dynamically loading interdependent components of executable code (such as plug-ins, bundles, etc.) in modern programming languages. In the Java(trademark) programming language, classes are dynamically loaded using a class loader as an application program executes. (xe2x80x9cJavaxe2x80x9d is a trademark of Sun Microsystems, Inc.) The class loader is responsible for searching for a particular class, and making that class available to the run-time system if found. Once loaded, each Java class object retains a reference to the class loader with which it was loaded. Java class loading is based on a delegation model, wherein a class loader first delegates the class loading responsibility to its immediate parent class loader. If neither that parent class loader nor any of its ancestors, in turn, are able to locate the class, then the initial class loader is used for the loading operation. Inheritance in the class loader chain is under control of the programmer, who may specify an explicit parent relationship when creating a new class loader. Each time a class loader is created, it is associated with one or more locations (such as file tree structures, archives, etc.) that it will be searching for classes.
FIGS. 1A-1C illustrate this prior art dynamic class loading technique with a simple example. Suppose that the following Java code is encountered while running code in the class named xe2x80x9cFooxe2x80x9d:
new Bar( )
That is, a new instance of the class named xe2x80x9cBarxe2x80x9d is to be instantiated. Using standard Java class loading, it is first necessary to determine the class loader used to load Foo. The Java code element 100 in FIG. 1A illustrates syntax which may be used for this purpose, wherein a variable xe2x80x9cCxe2x80x9d is assigned to the result of invoking the xe2x80x9cgetClassLoaderxe2x80x9d method on the Foo class. The next step is to use that class loader to load the class Bar. Syntax which may be used for this purpose is shown at 105, wherein the method xe2x80x9cloadClassxe2x80x9d on class loader C is invoked with xe2x80x9cBarxe2x80x9d as a parameter. The flowchart in FIG. 1C illustrates the logic with which this loadClass method operates. First, a check is made to see if Bar is already in this loader""s cache (Block 140). If so, then it is riot necessary to reload the class, and the located value (i.e. the class) is returned (Block 165). Otherwise, a recursive process begins (Block 145) where the parent of this class loader is asked to load the requested class.
For a class to be successfully loaded, the class loader used (or one of its ancestors) must be able to load all of the class"" superclasses and interfaces. As a result, if a superclass is loaded by a different loader, that loader must be a parent somewhere in the ancestor chain of the loader used to load the class (Bar, in this example). For example, with reference to the class loader hierarchy 110 in FIG. 1B, suppose the class loader responsible for loading class Foo is class loader xe2x80x9cCL3xe2x80x9d 125. This class loader therefore requests its parent class loader xe2x80x9cCL2xe2x80x9d 120 to load class Bar, and so on until either finding an already-loaded Bar or until no more ancestors remain to be checked. In the former case, the test in Block 150 has a positive result, and the located class is returned by Block 165. In the latter case, the test in Block 150 has a negative result and control reaches Block 155. At that point, the class path 120 for class Bar is determined (using the CLASSPATH variable), and a check is made (Block 160) to see if Bar can be located using that class path. If so, then the located class is loaded (BLOCK 170) and immediately initialized; otherwise, an error is returned (Block 175). After the class is loaded in Block 170, control returns to Block 165 to return the loaded class to the caller. This dynamic loading technique is well known in the computer programming art, and code to implement the class loader process is commonly provided as part of Java development toolkits.
There are a number of problems with this prior art class loading approach, however. Because the delegation model is linked to Java""s single inheritance class structure, a class loader parent chain must be able to load a complete Java type graph. This necessarily limits subsystems to only one prerequisite, and that prerequisite (and its ancestry) must be able to supply all of the subsystem""s ancestor classes: a complex composition of prerequisite components cannot be supported under this approach. In other words, the Java programmer needs to make sure that all type relationships implied in the class implementation (including extended classes, implemented interfaces, declared data member types, argument types of methods, return types of methods, etc.) can be loaded by its single loader chain. When dealing with complex functional relationships, the programmer typically addresses this problem by adding all the required archives, or xe2x80x9cjarxe2x80x9d files, on a single long class path. This is a less-than-optimal solution. Furthermore, components such as plug-ins are relatively xe2x80x9cheavyweightxe2x80x9d entities in that they require a considerable amount of resources (i.e. storage) to be allocated, take time to be initialized, and will often trigger the loading of many classes once initialized (which consumes more resources and takes additional time). This approach results in an inefficient use of resources in many cases, and increases the start-up time and the memory footprint of the program in which the plug-in is contained. For example, it may happen that some classes are not actually accessed until a relatively long time after activating the plug-in whose initialization triggered loading of the class, and some may never be accessed. These inefficiencies become especially significant in resource-constrained systems.
Other approaches to dynamic class loading, such as OSGi (xe2x80x9cOpen Services Gateway Initiativexe2x80x9d) bundles, use an independent class loader for each component, rather than using the delegation model which has been described with reference to FIGS. 1A-1C. However, OSGi bundles do not address the limitations of dynamic class loaders which have been discussed. OSGi bundles continue to rely on parent relationships during loading, and initialize upon start-up as well. (The term xe2x80x9cOSGi bundlesxe2x80x9d refers to components which adhere to the OSGi Service Gateway Specification. OSGi bundles are archive files containing class files and resources. A bundle""s manifest file identifies the bundle""s contents and also the packages and services which are imported and exported by that bundle. More information on this specification may be found on the Internet at location http://www.osgi.org/about/spec1.html.)
Accordingly, what is needed is an improved technique for dynamically loading independent components (that is, those components whose classes are not necessarily located within a single functional dependence hierarchy).
An object of the present invention is to provide an improved technique for dynamically loading independent code components.
Yet another object of the present invention is to provide an improved technique for loading components which are not located within a single functional dependence hierarchy chain.
Another object of the present invention is to provide a technique for dynamically loading components which supports complex prerequisites.
Still another object of the present invention is to provide a technique for dynamically loading components which allows explicitly specifying one or more prerequisite components.
A further object of the present invention is to provide a technique for dynamically loading components which delays initialization and loading of components until the component is needed.
Other objects and advantages of the present invention will be set forth in part in the description and in the drawings which follow and, in part, will be obvious from the description or may be learned by practice of the invention.
To achieve the foregoing objects, and in accordance with the purpose of the invention as broadly described herein, the present invention provides methods, systems, and computer program products for improving dynamic loading of components. In one aspect of preferred embodiments, this technique comprises: providing a specification of zero or more prerequisite components for components to be loaded; providing distinct class loaders associated with the components to be loaded; and attempting to load a class from a particular component using the provided class loader associated with that particular component, wherein the provided class loader may invoke class loaders associated with one or more of the prerequisite components if necessary.
Optionally, this technique may further comprise: providing multiple versions of a selected component to be loaded; loading one or more classes from two or more of the provided versions, wherein classes having duplicate names may therefore be loaded; and automatically distinguishing the classes having duplicate names by virtue of their distinct class loaders.
The specification of zero or more prerequisite components may further specify whether components re-export classes of their prerequisite components, and/or which classes of a particular component are to be exposed to other components for which the particular component is a prerequisite component.
In another aspect of preferred embodiments, the technique may comprise: providing distinct class loaders associated with the components to be loaded; monitoring attempts to use the distinct class loaders; and delaying activation of a particular component until the monitoring detects that the class loader associated with that particular component is loading its first class. Optionally, this aspect may be combined with the above-described aspect.
The present invention will now be described with reference to the following drawings, in which like reference numbers denote the same element throughout.